﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using Beeldbankmvc.Code;
using Beeldbankmvc.Helpers;
using Beeldbankmvc.Models;
using BeeldbankMVCTools;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using Beeldbankmvc.Controllers;
using Elmah;

namespace Beeldbankmvc.Models
{
    [HandleErrorWithELMAH]
    public class MediaObjectModel
    {
        private int ThumbnailWidth = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["FotoThumbnailWidth"]);
        private int PreviewWidth = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["FotoPreviewWidth"]);

        // TODO: testing moving bussiness logic to model this is just used for create, edit should use the same method
        MediaObjectRepository mediaObjectRepository = new MediaObjectRepository();
        SettingsRepository settingsRepository = new SettingsRepository();
        VideoQueueRepository videoQueueRepository = new VideoQueueRepository();

        BeeldbankLinqDataContext beeldBankDB = new BeeldbankLinqDataContext();

        public BEELDBANK_MEDIAOBJECT MediaObject { get; private set; }

        public void copyAndSaveMediaObjectModel(HttpRequestBase Request, string userName)
        {
            copyMediaObjectModel(MediaObject.Id, Request, userName);

            // get the file number
            MediaObject.FileNummer = settingsRepository.GetFileNumber();

            mediaObjectRepository.Add(this.MediaObject);
            mediaObjectRepository.Save();

            // update file number in the database
            settingsRepository.IncrementFileNumber();
        }

        public void copyMediaObjectModel(int id, HttpRequestBase Request, string userName)
        {
            // Save digital media item
            this.setRoles(Request);
            this.setStatus(Request);
            this.setMontage(Request);
            this.setType(Request);
            this.setCheckBoxUseInBanner(Request);
            this.setCheckBoxChecked(Request);
            this.setRelatedCollection(id, Request);
            this.setDateRealisatie(Request);

            // check which keywords are in the summery and add them to the keywords collection
            this.calculateKeyWords();

            if (!Roles.IsUserInRole("Administrator") && !Roles.IsUserInRole("EindRedacteur"))
            {
                MediaObject.modifiedby = userName;
                MediaObject.modifiedat = DateTime.Now;
            }
        }

        public void fillAndSaveMediaObjectModel(HttpRequestBase Request, string userName)
        {
            fillMediaObjectModel(MediaObject.Id, Request, userName);

            // get the file number
            MediaObject.FileNummer = settingsRepository.GetFileNumber();

            // Correct Description and Title
            string ErrorString = "";
            MediaObject.Omschrijving = MediaObjectTools.CorrectString(MediaObject.Omschrijving, true, ErrorString);
            MediaObject.Titel = MediaObjectTools.CorrectString(MediaObject.Titel, false, ErrorString);

            if (String.IsNullOrEmpty(MediaObject.AltTekst))
                MediaObject.AltTekst = AppHelper.convertHtmlStringToAltTag(MediaObject);

            mediaObjectRepository.Add(this.MediaObject);
            mediaObjectRepository.Save();

            // video queue requires MediaObject ID and FileNumber, only for existing media objects
            if (Request.Files["videoUpload"] != null && !String.IsNullOrEmpty(Request.Files["videoUpload"].FileName))
            {
                videoQueueRepository.Add(MediaObject.Id, MediaObject.FileNummer.Value, Request.Files["videoUpload"].FileName);
            }

            // update file number in the database
            settingsRepository.IncrementFileNumber();
        }

        public void fillMediaObjectModel(int id, HttpRequestBase Request, string userName)
        {
            // Save digital media item
            this.setFacets(id,Request);
            this.setRoles(Request);
            this.setStatus(Request);
            this.setMontage(Request);
            this.setType(Request);
            this.setCheckBoxUseInBanner(Request);
            this.setCheckBoxChecked(Request);
            this.setRelatedCollection(id, Request);
            this.setDateRealisatie(Request);
            this.SaveThumbnail(Request);
            this.SaveOrGenerateAltTekst(Request);

            // save queue item for existing media object
            if (Request.Files["videoUpload"] != null && MediaObject.Id != 0 && !String.IsNullOrEmpty(Request.Files["videoUpload"].FileName))
            {
                if (videoQueueRepository.FindOneByMediaObjectId(MediaObject.Id) == null)
                    videoQueueRepository.Add(MediaObject.Id, MediaObject.FileNummer.Value, Request.Files["videoUpload"].FileName);
            }

            // check which keywords are in the summery and add them to the keywords collection
            this.calculateKeyWords();

            if (!Roles.IsUserInRole("Administrator"))
                MediaObject.modifiedat = DateTime.Now;

            if (!Roles.IsUserInRole("Administrator") && !Roles.IsUserInRole("EindRedacteur"))
                MediaObject.modifiedby = userName;
        }

        public void SaveOrGenerateAltTekst(HttpRequestBase Request)
        {
            if(!String.IsNullOrEmpty(Request.Form["MediaObject.AltTekst"]))
            {
                MediaObject.AltTekst = Request.Form["MediaObject.AltTekst"];
            }
            else
            {
                MediaObject.AltTekst = AppHelper.convertHtmlStringToAltTag(MediaObject);
            }
        }

        public void setDropDownBoxes(HttpRequestBase Request)
        {
            // Set dropdown boxes to their previous state
            this.setRoles(Request);
            this.setStatus(Request);
            this.setMontage(Request);
            this.setType(Request);
        }
        
        public MediaObjectModel(BEELDBANK_MEDIAOBJECT mediaobject)
        {
            MediaObject = mediaobject;
        }

        public void DeleteFiles()
        {
            // Determine first part of the filePath
            int mapNumber = Convert.ToInt32(MediaObject.FileNummer) / Convert.ToInt32(ConfigurationManager.AppSettings["MaxFotosInDirectory"]);
            // Determine first part of the filePath
            string fileName = ConfigurationManager.AppSettings["FotoArchive"] + "\\" + mapNumber.ToString();
            DeleteFilesFromDirectory(fileName);
            fileName = ConfigurationManager.AppSettings["FileArchive"] + "\\" + mapNumber.ToString();
            DeleteFilesFromDirectory(fileName);
            fileName = ConfigurationManager.AppSettings["VideoArchive"] + "\\" + mapNumber.ToString();
            DeleteFilesFromDirectory(fileName);
        }

        public void DeleteFilesFromDirectory(string fileName)
        {
            // Check if directory exists
            Tools.CheckDir(fileName);
            // Get all files in this directory
            string[] filePaths = Directory.GetFiles(fileName);
            foreach (string filePath in filePaths)
            {
                // Split the file path
                String[] fileNameParts = filePath.Split('\\');
                // Get the file name
                string file = fileNameParts[fileNameParts.Length - 1];
                // Delete everyting with [number].[extention] and special files
                if (file.StartsWith(MediaObject.FileNummer + ".") ||
                    file.StartsWith(MediaObject.FileNummer + "s.") ||
                    file.Contains(MediaObject.FileNummer + "_[") ||
                    file.StartsWith(MediaObject.FileNummer + "f.") ||
                    file.StartsWith(MediaObject.FileNummer + "_C.") ||
                    file.StartsWith(MediaObject.FileNummer + "_HQ."))
                {
                    try
                    {
                        // Deleting the file
                        File.Delete(filePath);
                    }
                    catch (Exception ex)
                    {
                        // Log exception
                        ex.Data.Add("filePath", filePath);
                        var context = HttpContext.Current;
                        ErrorLog.GetDefault(context).Log(new Error(ex, context));
                    }
                }
            }
        }
        
        // Save image and thumbnail
        public void SaveThumbnail(HttpRequestBase Request)
        {
            foreach (string inputTagName in Request.Files)
            {
                HttpPostedFileBase file = Request.Files[inputTagName];
                if (file.ContentLength > 0)
                {
                    if (inputTagName.Equals("imageUpload") || inputTagName.Equals("fileImageUpload"))
                    {
                        // Determine extension
                        string extension = file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
                        // Determine first part of the filename
                        int mapNumber = Convert.ToInt32(MediaObject.FileNummer) / Convert.ToInt32(ConfigurationManager.AppSettings["MaxFotosInDirectory"]);
                        // Determine first part of the filename
                        string fileName = "";
                        fileName = ConfigurationManager.AppSettings["FotoArchive"] + "\\" + mapNumber.ToString();
                        // Check if directory exists
                        Tools.CheckDir(fileName);
                        // Creeer de nieuwe filenaam en forceer de juiste extensie
                        // Complete the filename for the full version
                        fileName += "\\" + MediaObject.FileNummer.ToString();
                        if ((extension == "jpg") || (extension == "tif"))
                        {
                            // Complete the filename for the full version
                            fileName += "." + extension;
                            // Upload the image in the current format and correct extension
                            file.SaveAs(fileName);
                        }
                        else
                        {
                            // Set extension to JPG
                            extension = "jpg";
                            // Complete the filename for the full version
                            fileName += "." + extension;
                            // Create a temporary filename
                            string fileNameTmp = "";
                            fileNameTmp = ConfigurationManager.AppSettings["FotoArchive"] + "\\" + mapNumber.ToString() + "\\" + MediaObject.FileNummer.ToString() + ".tmp";
                            // Upload the image in the current format and temporary filename
                            file.SaveAs(fileNameTmp);
                            // Create an image in memory from the source file
                            Bitmap bmp = (Bitmap)Image.FromFile(fileNameTmp);
                            // Save the image file from memory and convert it to a jpg file and save it in the destination directory
                            bmp.Save(fileName, ImageFormat.Jpeg);
                            bmp.Dispose();
                            // Remove the temporary image
                            File.Delete(fileNameTmp);
                        }

                        // Create a thumbnail in memory from the source file that was just recently created or moved
                        MediaObject.Thumbnail = ImageManipulation.ReadBitmap2ByteArray(ImageManipulation.CreateThumbnail(fileName, ThumbnailWidth, 0));

                        // create MediaServiceController
                        MediaServiceController mediaServiceController = new MediaServiceController();
                        mediaServiceController.CreateImage("[250x250-" + MediaObject.FileNummer.ToString() + "].jpg");
                        mediaServiceController.CreateImage("[600-" + MediaObject.FileNummer.ToString() + "].jpg");
                    }
                    else if (inputTagName.Equals("fileUpload"))
                    {
                        // Determine extension
                        string extension = file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
                        // Determine first part of the filename
                        int mapNumber = Convert.ToInt32(MediaObject.FileNummer) / Convert.ToInt32(ConfigurationManager.AppSettings["MaxFotosInDirectory"]);
                        // Determine first part of the filename
                        string fileName = ConfigurationManager.AppSettings["FileArchive"] + "\\" + mapNumber.ToString();
                        // Check if directory exists
                        Tools.CheckDir(fileName);
                        // Creeer de nieuwe filenaam en forceer de juiste extensie
                        // Complete the filename for the full version
                        fileName += "\\" + MediaObject.FileNummer.ToString() + "." + extension;

                        file.SaveAs(fileName);
                    }
                    else if (inputTagName.Equals("videoUpload") || inputTagName.Equals("subtitlesUpload") || inputTagName.Equals("audioUpload") || inputTagName.Equals("videoImageUpload"))
                    {
                        // Determine extension
                        string extension = file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
                        // Determine first part of the filename
                        int mapNumber = Convert.ToInt32(MediaObject.FileNummer) / Convert.ToInt32(ConfigurationManager.AppSettings["MaxFotosInDirectory"]);
                        // Determine first part of the filename
                        string fileName = ConfigurationManager.AppSettings["VideoArchive"] + "\\" + mapNumber.ToString();
                        // Check if directory exists
                        Tools.CheckDir(fileName);


                        string path = "";
                        path = ConfigurationManager.AppSettings["VideoArchiveStandbyMovies"];
                        // Check if directory exists and if a video is changed or uploaded, only in this last case do videos need to be regenerated
                        if (Directory.Exists(path) && inputTagName.Equals("videoUpload"))
                        {
                            string[] dummyVideos = Directory.GetFiles(path);
                            foreach (string dummyVideo in dummyVideos)
                            {
                                String onlyfile = dummyVideo.Substring(dummyVideo.LastIndexOf('\\') + 1);
                                string dummyExtension = onlyfile.Split('.')[1]; //get the extention

                                // To copy a file to another location and 
                                // overwrite the destination file if it already exists. but not the one being uploaded by the user !!!
                                if (!extension.ToUpperInvariant().Equals(dummyExtension.ToUpperInvariant()))
                                {
                                    System.IO.File.Copy(dummyVideo, fileName + "\\" + MediaObject.FileNummer.ToString() + "." + dummyExtension, true);
                                }
                            }
                        }

                        // Creeer de nieuwe filenaam en forceer de juiste extensie
                        // Complete the filename for the full version
                        fileName += "\\" + MediaObject.FileNummer.ToString() + "." + extension;

                        file.SaveAs(fileName);
                    }
                }
            }
        }

        // TODO: set related collection items
        public void setRelatedCollection(int id, HttpRequestBase Request)
        {
            // clear existing relationship between the media object and its collection
            var test = from b in beeldBankDB.BEELDBANK_MEDIAOBJECT_COLLECTIONs
                       where b.MediaObjectId == id
                       select b;

            foreach (var item in test)
                beeldBankDB.BEELDBANK_MEDIAOBJECT_COLLECTIONs.DeleteOnSubmit(item);

            beeldBankDB.SubmitChanges();
            
            // TODO: put code below in the repository
            // maybe add a check to see if duplicate items are being added

            String SelectedCollectionItems = Request.Form["SelectedCollectionItems"];
            if (!String.IsNullOrEmpty(SelectedCollectionItems))
            {
                String[] SelectedCollectionItem = SelectedCollectionItems.Split(',');

                foreach (String CollectionItemId in SelectedCollectionItem)
                {
                    // Adding a related collection
                    BEELDBANK_MEDIAOBJECT_COLLECTION relatedCollection = new BEELDBANK_MEDIAOBJECT_COLLECTION();
                    relatedCollection.CollectionId = int.Parse(CollectionItemId);
                    if (!MediaObject.BEELDBANK_MEDIAOBJECT_COLLECTIONs.Contains(relatedCollection, new MyCollectionObjectComparer()))
                        MediaObject.BEELDBANK_MEDIAOBJECT_COLLECTIONs.Add(relatedCollection);
                }
            }
        }

        public void setCheckBoxUseInBanner(HttpRequestBase Request)
        {
            if (Request.Form["MediaObject.UseInBanner"] != null && Request.Form["MediaObject.UseInBanner"].Equals("true"))
                MediaObject.UseInBanner = true;
            else
                MediaObject.UseInBanner = false;
        }

        public void setCheckBoxChecked(HttpRequestBase Request)
        {
            if (Request.Form["MediaObject.Checked"] != null && Request.Form["MediaObject.Checked"].Equals("true"))
                MediaObject.Checked = true;
            else
                MediaObject.Checked = false;
        }

        public void setStatus(HttpRequestBase Request)
        {
            if (!String.IsNullOrEmpty(Request.Form["Statuses"]))
                MediaObject.StatusId = int.Parse(Request.Form["Statuses"]);
        }

        public void setMontage(HttpRequestBase Request)
        {
            if (!String.IsNullOrEmpty(Request.Form["Montage"]))
                MediaObject.Montage = Request.Form["Montage"];
        }

        public void setFacets(int Id, HttpRequestBase Request)
        {
            FacetRepository facetRepository = new FacetRepository();

            facetRepository.UpdateOrInsert(MediaObject, Id, Request.Form["regioFacets"], Request.Form["techniekFacets"], Request.Form["riviergebiedFacets"], Request.Form["projectFacets"]);
            facetRepository.Save();
        }
        
        public void setRoles(HttpRequestBase Request)
        {
            MediaObject.GroepRechten = Request.Form["RolesList"];
        }

        public void setDateRealisatie(HttpRequestBase Request)
        {
            IFormatProvider culture = new CultureInfo("nl-NL", true);
            DateTime dt;
            try
            {
                dt = DateTime.ParseExact(Request.Form["MediaObject.Datum_Realisatie"].ToString(), "dd-MM-yyyy", culture);
                if (dt > DateTime.Today)
                    MediaObject.Datum_Realisatie = DateTime.Today;
                else
                    MediaObject.Datum_Realisatie = dt;
            }
            catch
            {
                // reset to Onbekend
                dt = Convert.ToDateTime("01-01-1900");
                MediaObject.Datum_Realisatie = dt;
            }
        }

        public void setType(HttpRequestBase Request)
        {
            if (!String.IsNullOrEmpty(Request.Form["Types"]))
            {
                MediaObject.TypeId = int.Parse(Request.Form["Types"]);

                if ((MediaObject.TypeId == 20) && String.IsNullOrEmpty(MediaObject.Montage))
                {
                    MediaObject.Montage = "Gemonteerd, 16x9 (400)";
                }
            }
        }

        public void calculateKeyWords()
        {
            #region AddingKeyWordsAndCategories
            // test
            // TODO: move to repository
            String description = MediaObject.Omschrijving + " " + MediaObject.Titel;

            description = AppHelper.filterOutHTML(description, " ");
            description = AppHelper.filterOutSpecialCharacters(description);

            if (!String.IsNullOrEmpty(description))
            {
                description = description.Replace("\r", " ");
                description = description.Replace("\n", " ");
                String[] descritionWords = description.Split(' ');

                var keywords =
                    from c in mediaObjectRepository.GetDataContext().BEELDBANK_WORDs
                    select c.Word;

                var foundKeyWords = descritionWords.Intersect(keywords, StringComparer.CurrentCultureIgnoreCase);

                // keywords are always regenerated from the description text
                MediaObject.Trefwoorden = "";
                foreach (var x in foundKeyWords)
                {
                    MediaObject.Trefwoorden += x + " | ";
                }

                // Loop trough all collections and create a custom collection object
                var collections = from a in mediaObjectRepository.GetDataContext().BEELDBANK_COLLECTIONs select new { keyword = a.Keywords, name = a.Name, id = a.Id };

                CollectionRepository CollectionRepository = new CollectionRepository();

                // loop trough the collection object
                foreach (var coll in collections)
                {
                    // get a key words array from the keywords column 
                    string[] keywordStringWords = coll.keyword.Split('|');

                    // check is the foundKeywords of this item are in this collection
                    var foundKeyWordsInThisCollection = keywordStringWords.Intersect(foundKeyWords, StringComparer.CurrentCultureIgnoreCase);

                    // add this collection to the mediaObject

                    foreach (var x in foundKeyWordsInThisCollection)
                    {
                        // test adding a related collection
                        BEELDBANK_MEDIAOBJECT_COLLECTION relatedCollection = new BEELDBANK_MEDIAOBJECT_COLLECTION();
                        relatedCollection.CollectionId = coll.id;


                        if (!MediaObject.BEELDBANK_MEDIAOBJECT_COLLECTIONs.Contains(relatedCollection, new MyCollectionObjectComparer()))
                        {
                            MediaObject.BEELDBANK_MEDIAOBJECT_COLLECTIONs.Add(relatedCollection);
                        }
                    }
                }
            }
            #endregion AddingKeyWordsAndCategories
        }

        public class MyCollectionObjectComparer : IEqualityComparer<BEELDBANK_MEDIAOBJECT_COLLECTION>
        {
            public bool Equals(BEELDBANK_MEDIAOBJECT_COLLECTION a, BEELDBANK_MEDIAOBJECT_COLLECTION b)
            {
                return a.CollectionId == b.CollectionId;
            }

            public int GetHashCode(BEELDBANK_MEDIAOBJECT_COLLECTION collectionObject)
            {
                return collectionObject.CollectionId.GetHashCode();
            }
        }
    } 

}
